package com.zjxf.exception;


import com.zjxf.base.common.JSONResponse;
import com.zjxf.base.common.OperationException;
import com.zjxf.base.common.SystemStatusCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.format.DateTimeParseException;
import java.util.Objects;
import java.util.Set;

/**
 * 全局异常捕获类
 *
 * @author fhx
 */
@Slf4j
@RestControllerAdvice//全局的异常捕获 返回json格式
public class ControllerExceptionHandler {

    @Resource
    private HttpServletRequest request;

    /**
     * 400状态码
     */
    private static Integer code400 = SystemStatusCode.SC_BAD_REQUEST.getCode();

    /**
     * 500状态码
     */
    private static Integer code500 = SystemStatusCode.SC_INTERNAL_SERVER_ERROR.getCode();

    /**
     * 成功
     */
    private static Integer code200 = SystemStatusCode.SUCCESS.getCode();

    /**
     * 无权限访问
     */
    private static Integer code401 = SystemStatusCode.SC_UNAUTHORIZED.getCode();

    /**
     * 错误的请求方式
     *
     * @param ex 异常
     * @return Result
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public JSONResponse httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
        error(ex.getMessage());
        ex.printStackTrace();
        return JSONResponse.error(code500, ex.getMessage());
    }

    /**
     * io错误
     *
     * @param ex 异常
     * @return Result
     */
    @ExceptionHandler(IOException.class)
    public JSONResponse iOException(IOException ex) {
        error(ex.getMessage());
        ex.printStackTrace();
        return JSONResponse.error(code500, ex.getMessage());
    }

    /**
     * 文件太大异常
     *
     * @param ex 异常
     * @return ResultMessage
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public JSONResponse maxUploadSizeExceededException(MaxUploadSizeExceededException ex) {
        error(ex.getMessage());
        return JSONResponse.error(code500, "文件太大，请重新选择文件");
    }

    /**
     * 对象参数验证没通过异常
     *
     * @param e 异常
     * @return 自定义message
     */
    @ExceptionHandler(BindException.class)
    private JSONResponse bindExceptionHandler(BindException e) {
        String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
        error(message);
        return JSONResponse.error(code200, message);
    }

    /**
     * 单属性验证未通过异常
     *
     * @param e 异常
     * @return Result
     */
    @ExceptionHandler(ConstraintViolationException.class)
    private JSONResponse constraintViolationExceptionHandler(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> violationSet = e.getConstraintViolations();
        String message = violationSet.stream().findFirst().map(ConstraintViolation::getMessage).orElse("");
        error(message);
        return JSONResponse.error(code200, message);
    }

    /**
     * 单属性验证未通过异常
     *
     * @param e 异常
     * @return 自定义message
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    private JSONResponse methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        String message = bindingResult.getFieldError().getDefaultMessage();
        error(message);
        return JSONResponse.error(code200, message);
    }

    /**
     * 自定义异常捕获
     *
     * @param e 异常
     * @return Result
     */
    @ExceptionHandler(OperationException.class)
    private JSONResponse operationException(OperationException e) {
        error(e.getMessage());
        return JSONResponse.error(code200, e.getMessage());
    }

    /**
     * 必要参数异常捕获
     *
     * @param e 异常
     * @return Result
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    private JSONResponse missingServletRequestParameterException(MissingServletRequestParameterException e) {
        String parameterName = e.getParameterName();
        String parameterType = e.getParameterType();
        StringBuilder message = new StringBuilder().append("必要的").append(parameterType).append("类型参数'").append(parameterName).append("'不存在");
        error(message.toString());
        return JSONResponse.error(code200, message.toString());
    }

    /**
     * 类型转换异常
     *
     * @param e 异常
     * @return Result
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public JSONResponse httpMessageNotReadableException(HttpMessageNotReadableException e) {
        error(e.getMessage());
        e.printStackTrace();
        return JSONResponse.error(code200, "类型转换失败,请确认参数类型是否一致");
    }

    /**
     * 时间转换异常
     *
     * @param e 异常
     * @return Result
     */
    @ExceptionHandler(DateTimeParseException.class)
    public JSONResponse dateTimeParseException(DateTimeParseException e) {
        error(e.getMessage());
        e.printStackTrace();
        return JSONResponse.error(code200, "时间转换失败,时间的格式不正确");
    }

    /**
     * 文件未找到
     *
     * @param e 文件未找到异常信息
     * @return Result
     */
    @ExceptionHandler(FileNotFoundException.class)
    public JSONResponse FileNotFoundException(FileNotFoundException e) {
        error(e.getMessage());
        return JSONResponse.error(code200, "一个不存在的文件");
    }

    /**
     * 链接未返回就关闭
     *
     * @param e 文件未找到异常信息
     */
    @ExceptionHandler(ClientAbortException.class)
    public void FileNotFoundException(ClientAbortException e) {
        error(e.getMessage());
    }

    public void error(String msg) {
        log.error("请求url-->{}; message:-->{}", request.getRequestURI(), msg);
    }
}
